# -*- coding: utf-8 -*-
import Globals


# 히스토리 리스트에 넣을때:
# cmd = {커맨드타입:redo/undo 함수에 인자로 건네어질 data}
# self.AddCmd(cmd)
#
# ex)
# cmd = {CMD_INSERT:{"pos" : pos, "word" : word}}
# self.AddCmd(cmd)
#

# 커맨드는 CMD_INSERT, CMD_DELETE, CMD_REPLACE 만 있으면 되지 않을까
#    생각해보면 CMD_REPLACE로 다 되지 않을까? 
#    CMD_INSERT : "aaa" insert => ""를 "aaa"로 replace 
#    CMD_DELETE : "aaa" delete => "aaa"를 ""로 replace
#
# todo: singleton 해보기
# todo: text 셋팅을 여기서 직접하는데, 따로 레이어를 추가해서 해보기


(CMD_INSERT, CMD_DELETE, CMD_REPLACE) = range(3)
(REDO_FUNC, UNDO_FUNC) = range(2)
(POSITION, VALUE, VALUE_NEW) = ("pos", "value", "value_new")

class HistoryManager:
    redoUndoFuncs = {
                       CMD_INSERT : {REDO_FUNC : "RedoInsert"
                                     , UNDO_FUNC : "UndoInsert"}
                       , CMD_DELETE : {REDO_FUNC : "RedoDelete"
                                       , UNDO_FUNC : "UndoDelete"}
                       , CMD_REPLACE : {REDO_FUNC : "RedoReplace"
                                        , UNDO_FUNC : "UndoReplace"}
                       }
    
    # command history list
    cmdList = []
    
    # pointer for command history list(cmdList)
    # start ptr = 0 (it's empty)
    cmdsIdx = 0
    
    def __init__(self):
        pass

    #===========================================================================
    # Add Command Functions
    #===========================================================================
    
    def AddCmd(self, cmd):
        # 새로운 커맨드가 왔으므로 히스토리 리스트에서 현재 포인터 이후는 모두 제거
        if len(self.cmdList) > self.cmdsIdx:
            self.cmdList = self.cmdList[:self.cmdsIdx]

        self.cmdList.append(cmd)
        self.cmdsIdx += 1
    
    def AddInsertCmd(self, pos, word):
        cmd = {CMD_INSERT:{POSITION : pos, VALUE : word}}
        self.AddCmd(cmd)
    
    def AddDeleteCmd(self, pos, word):
        cmd = {CMD_DELETE:{POSITION : pos, VALUE : word}}
        self.AddCmd(cmd)
        
    def AddReplaceCmd(self, pos, wordOrg, wordNew):
        cmd = {CMD_REPLACE:{POSITION : pos, VALUE : wordOrg, VALUE_NEW : wordNew}}
        self.AddCmd(cmd)
        
    #===========================================================================
    # Redo/Undo Functions
    #===========================================================================
    
    def RedoInsert(self, args):
        pos = args[POSITION]
        word = args[VALUE]
        Globals.textControl.Replace(pos, pos + len(word), word)
                                    
    def UndoInsert(self, args):
        pos = args[POSITION]
        word = args[VALUE]
        Globals.textControl.Replace(pos, pos + len(word), "")

    def RedoDelete(self, args):
        self.UndoInsert(args)
    
    def UndoDelete(self, args):
        pos = args[POSITION]
        word = args[VALUE]
        Globals.textControl.Replace(pos, pos, word)
        
    def RedoReplace(self, args):
        pos = args[POSITION]
        word = args[VALUE]
        wordNew = args[VALUE_NEW]
        Globals.textControl.Replace(pos, pos + len(word), wordNew)
        
    def UndoReplace(self, args):
        pos = args[POSITION]
        word = args[VALUE]
        wordNew = args[VALUE_NEW]
        Globals.textControl.Replace(pos, pos + len(wordNew), word)
    
    def Undo(self):
        if self.CanUndo():
            cmd = self.cmdList[self.cmdsIdx - 1]
            (cmdType, args) = cmd.items()[0]
            if self.redoUndoFuncs.has_key(cmdType):
                undoFuncStr = self.redoUndoFuncs[cmdType][UNDO_FUNC]
                if hasattr(self, undoFuncStr):
                    getattr(self, undoFuncStr)(args)
                    self.cmdsIdx -= 1
                    
    #===========================================================================
    # Helper Functions
    #===========================================================================
    
    def CanUndo(self):
        if self.cmdsIdx > 0:
            return True
        return False
    
    def Redo(self):
        if self.CanRedo():
            cmd = self.cmdList[self.cmdsIdx]
            (cmdType, args) = cmd.items()[0]
            if self.redoUndoFuncs.has_key(cmdType):
                redoFuncStr = self.redoUndoFuncs[cmdType][REDO_FUNC]
                if hasattr(self, redoFuncStr):
                    getattr(self, redoFuncStr)(args)
                    self.cmdsIdx += 1
    
    def CanRedo(self):
        return len(self.cmdList) > 0 and self.cmdsIdx < len(self.cmdList)
    
    def ToString(self, idx):
        str = ""
        if idx in range(0,len(self.cmdList)):
            str += "%d: " % idx
            cmd = self.cmdList[idx]
            (cmdType,args) = cmd.items()[0]
            if cmdType == CMD_INSERT:
                str += "Ins "
            elif cmdType == CMD_DELETE:
                str += "Del "
            elif cmdType == CMD_REPLACE:
                str += "Rep "
            
            str += ("%d %c") % (args[POSITION], args[VALUE])
        return str
        
    def ShowAll(self):
        str = "cur :%d \r\n" % self.cmdsIdx
        for idx in range(0,len(self.cmdList)):
            str += self.ToString(idx) + "\r\n"
        return str
            
